import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dartx/dartx.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:open_settings_plus/open_settings_plus.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:realm/realm.dart';
import 'package:sgy_flutter/ble/ble_manager.dart';
import 'package:sgy_flutter/ble/right_ble_manager.dart';
import 'package:sgy_flutter/database/device_entity.dart';
import 'package:sgy_flutter/extensions/get.dart';
import 'package:sgy_flutter/main.dart';
import 'package:sgy_flutter/model/device_model.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:sgy_flutter/model/device_type.dart';
import 'package:sgy_flutter/model/product_type.dart';
import 'package:sgy_flutter/page/detail/view.dart';
import 'package:sgy_flutter/widget/app_dialog.dart';
import 'package:rxdart/rxdart.dart' as rx;
import 'package:synchronized/synchronized.dart';

class HomeLogic extends GetxController {
  var appVersion = "".obs;

  RxList<DeviceModel> items = RxList<DeviceModel>.empty(growable: true);

  var lock = new Lock();

  @override
  void onReady() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    String version = packageInfo.version;
    appVersion(version);

    realm.all<RealmDeviceEntity>().changes.listen((results) {
      List<DeviceModel> list = List.empty(growable: true);
      Set<String> connectedAddressSet = Set();
      Map<String, num?> rssiMap = Map();
      Set<String> inTransportModeSet = Set();
      for (var item in items) {
        rssiMap[item.address] = item.rssi;
        if (item.rightDeviceModel?.address != null) {
          rssiMap[item.rightDeviceModel!.address] = item.rightDeviceModel?.rssi;
        }
        if (item.rightDeviceModel?.connected == true) {
          connectedAddressSet.add(item.rightDeviceModel!.address);
        }
        if (item.connected == true) {
          connectedAddressSet.add(item.address);
        }
        if (item.inTransportMode == true) {
          inTransportModeSet.add(item.address);
        }
      }
      for (var entity in results.results) {
        var device = DeviceModel.fromEntity(entity);
        device = device.copyWith(rssi: rssiMap[device.address]);
        if (connectedAddressSet.contains(device.address)) {
          device = device.copyWith(connected: true);
        }
        if (inTransportModeSet.contains(device.address)) {
          device = device.copyWith(inTransportMode: true);
        }
        list.add(device);
      }
      printInfo(info: "list:${list}");
      lock.synchronized(() {
        items.clear();
        items.addAll(DeviceModel.filterRightPart(list));
      });
    });

    debounce(bleManager.scanResults, _handleScanResults,
        time: Duration(seconds: 1));
    bleManager.onConnectionStateChanged.listen(_handleOnConnectionStateChanged);
    bleManager.startScan();
    final List<ConnectivityResult> connectivityResult =
        await (Connectivity().checkConnectivity());
    if (connectivityResult.contains(ConnectivityResult.none)) {
      Get.dialog(
          AppDialog(
            title: "提示".tr,
            message: "App没有网络,请前往设置".tr,
            submit: "前往设置".tr,
            onSubmit: () {
              switch (OpenSettingsPlus.shared) {
                case OpenSettingsPlusAndroid():
                  OpenSettingsPlusAndroid().wifi();
                  break;
                case OpenSettingsPlusIOS():
                  OpenSettingsPlusIOS().wifi();
                  break;
              }
            },
          ),
          barrierDismissible: false);
    }

    // Permission.network.status;
    super.onReady();
  }

  void _tryToScanForRSSI() {
    if (items.isNotEmpty && Get.currentRoute == "/MainPage") {
      bleManager.startScan();
    }
  }

  void _handleOnConnectionStateChanged(OnConnectionStateChangedEvent event) {
    lock.synchronized(() {
      final index =
          items.indexWhere((test) => test.address == event.device.remoteId.str);
      if (index != -1) {
        printError(
            info:
                "_handleOnConnectionStateChanged:${event.device.advName}-${event.connectionState}");
        var model = items.removeAt(index);
        items.insert(
            index,
            model.copyWith(
                connected: event.connectionState ==
                    BluetoothConnectionState.connected));
      } else {
        final index = items.indexWhere((test) =>
            test.rightDeviceModel?.address == event.device.remoteId.str);
        var model = items.removeAt(index);
        items.insert(
            index,
            model.copyWith(
                rightDeviceModel: model.rightDeviceModel?.copyWith(
                    connected: event.connectionState ==
                        BluetoothConnectionState.connected)));
      }
    });
  }

  void _handleScanResults(List<DeviceModel> value) {
    lock.synchronized(() {
      for (var i = 0; i < items.length; i++) {
        var model = items[i];
        var hasScanResult = false;
        if (bleManager.deviceModel?.address == model.address &&
            bleManager.rssi.value != null) {
          hasScanResult = true;
          items.replaceRange(i, i + 1, [
            model.copyWith(
                rssi: bleManager.rssi.value,
                connected: model.connected,
                inTransportMode: model.inTransportMode)
          ]);
        }
        for (var result in value) {
          if (model.address == result.address) {
            hasScanResult = true;
            items.replaceRange(i, i + 1, [
              model.copyWith(
                  rssi: result.rssi,
                  connected: model.connected,
                  inTransportMode: result.inTransportMode)
            ]);
            if (model.name.length < result.name.length) {
              _saveOrUpdateEntity(model
                  .copyWith(
                      name: result.name,
                      deviceID: result.deviceID,
                      deviceSN: result.deviceSN,
                      inTransportMode: result.inTransportMode)
                  .toEntity());
            }
          }

          if (model.rightDeviceModel?.address == result.address) {
            hasScanResult = true;
            var rightModel = model.rightDeviceModel?.copyWith(
                rssi: result.rssi,
                connected: model.connected,
                inTransportMode: result.inTransportMode);
            items.replaceRange(
                i, i + 1, [model.copyWith(rightDeviceModel: rightModel)]);
            if (model.name.length < result.name.length) {
              _saveOrUpdateEntity(rightModel!
                  .copyWith(
                      name: result.name,
                      inTransportMode: result.inTransportMode,
                      deviceID: result.deviceID,
                      deviceSN: result.deviceSN)
                  .toEntity());
            }
          }
        }
        if (!hasScanResult) {
          items.replaceRange(i, i + 1, [
            model.copyWith(
              rssi: null,
              connected: model.connected,
            )
          ]);
        }
      }
    });
  }

  void deleteItem(DeviceModel model) async {
    bleManager.disconnectLast(null);
    rightBleManager?.disconnectLast(null);
    void del(model) async {
      final entity = await realm
          .all<RealmDeviceEntity>()
          .query("address == '${model.address}'")
          .changes
          .first;
      if (entity.results.isNotEmpty) {
        realm.writeAsync(() {
          realm.delete(entity.results.first);
        });
      }
    }

    if (model.rightDeviceModel != null) {
      del(model.rightDeviceModel);
    }
    del(model);
  }

  void deleteAll() {
    bleManager.disconnectLast(null);
    rightBleManager?.disconnectLast(null);
    realm.writeAsync(() {
      realm.deleteAll<RealmDeviceEntity>();
    });
  }

  void startScan() {
    loaderOverlay?.hide();
    bleManager.startScan();
  }

  Future stopScan() async {
    await bleManager.stopScan();
  }

  /**
   * 只有当硬件版本没有的时候才会去更新，固件版本请在里面去获取
   */
  Future _updateDeviceInfo(BleManager manager, DeviceModel model) async {
    if (model.hardware == null || model.hardware?.isEmpty == true) {
      final deviceInfo = await manager.deviceInfoService.readDeviceInfo();

      final entity = await realm
          .all<RealmDeviceEntity>()
          .query("address == '${model.address}'")
          .changes
          .first;
      if (entity.results.isNotEmpty) {
        model.hardware = deviceInfo.hardwareRevision;
        model.firmware = deviceInfo.firmwareRevision;
        final saveEntity = model.toEntity(id: entity.results.first.id);
        realm.writeAsync(() {
          realm.add(saveEntity, update: true);
        });
      }
    }
  }

  void connect(DeviceModel model) async {
    loaderOverlay?.show(progress: "连接中".tr);
    try {
      await stopScan();

      await bleManager.disconnectLast(model);
      await rightBleManager.disconnectLast(
          model.deviceType == DeviceType.dlsR ? model : model.rightDeviceModel);
      await Future.delayed(Duration(milliseconds: 50));
      var hasOneConnected = false;
      if (model.productType == ProductType.dls) {
        DeviceModel? leftModel =
            model.deviceType == DeviceType.dlsL ? model : null;
        DeviceModel? rightModel =
            model.deviceType == DeviceType.dlsR ? model : null;
        rightModel ??= leftModel?.rightDeviceModel;
        //重复3次，每次间隔100毫秒
        int count = 3;
        while (rightModel == null || leftModel == null) {
          //没有左边
          for (final scanResult in bleManager.scanResults) {
            final otherModel = scanResult;
            if (model.deviceType == DeviceType.dlsL &&
                model.isRightDevice(otherModel)) {
              leftModel = model;
              rightModel = otherModel;
              break;
            }
            if (model.deviceType == DeviceType.dlsR &&
                model.isLeftDevice(otherModel)) {
              leftModel = otherModel;
              rightModel = model;
              break;
            }
          }
          if (rightModel == null || leftModel == null) {
            await Future.delayed(Duration(milliseconds: 100));
          }
          count -= 1;
          if (count == 0) {
            break;
          }
        }
        printInfo(info: "leftModel:$leftModel,rightModel:$rightModel");
        if (leftModel != null && rightModel != null) {
          await bleManager.connect(leftModel);
          await _updateDeviceInfo(bleManager, leftModel);
          final rightObjectId =
              await _saveOrUpdateEntity(rightModel.toEntity());
          leftModel.isDoubleSlide = true;
          final leftEntity = leftModel.toEntity();
          leftEntity.rightDeviceId = rightObjectId;
          await _saveOrUpdateEntity(leftEntity);

          await rightBleManager.connect(rightModel);
          await _updateDeviceInfo(rightBleManager, rightModel);
          hasOneConnected = true;
        } else if (leftModel != null && rightModel == null) {
          await bleManager.connect(leftModel);
          await _updateDeviceInfo(bleManager, leftModel);
          hasOneConnected = true;
        } else if (leftModel == null && rightModel != null) {
          await rightBleManager.connect(rightModel);
          await _updateDeviceInfo(rightBleManager, rightModel);
          hasOneConnected = true;
        }
      } else {
        //没有双边设备的简单点
        await bleManager.connect(model);
        await _updateDeviceInfo(bleManager, model);
        hasOneConnected = true;
      }

      await Future.delayed(Duration(milliseconds: 200));
      loaderOverlay?.hide();
      if (hasOneConnected) {
        printInfo(info: "enterDetailPage:${model}");
        await Get.to(() => DetailPage(),
            arguments: model, routeName: "detail", popGesture: false);
      } else {
        Get.dialog(
            AppDialog(
                title: "连接失败，请检查".tr,
                message: "1.设备是否已转动唤醒。\n2.设备是否有电。\n3.功率计请不要在充电状态下连接APP。".tr,
                submit: "好的，我知道了！".tr),
            barrierDismissible: false);
      }
      startScan();
    } on FlutterBluePlusException catch (e) {
      loaderOverlay?.hide();
      startScan();
      printError(info: "$e");
      Get.dialog(
          AppDialog(
              title: "连接失败，请检查".tr,
              message: "1.设备是否已转动唤醒。\n2.设备是否有电。\n3.功率计请不要在充电状态下连接APP。".tr,
              submit: "好的，我知道了！".tr),
          barrierDismissible: false);
    } catch (e) {
      loaderOverlay?.hide();
      startScan();
      printError(info: "$e");
      Get.dialog(
          AppDialog(
              title: "连接失败，请检查".tr,
              message: "1.设备是否已转动唤醒。\n2.设备是否有电。\n3.功率计请不要在充电状态下连接APP。".tr,
              submit: "好的，我知道了！".tr),
          barrierDismissible: false);
    } finally {}
  }

  void disconnect(DeviceModel model) async {
    loaderOverlay?.show();
    try {
      await bleManager.disconnect(model);
      await rightBleManager?.disconnectLast(null);
      await Future.delayed(Duration(milliseconds: 200));
    } catch (e) {
      printError(info: "$e");
    } finally {
      loaderOverlay?.hide();
    }
  }

  Future<ObjectId> _saveOrUpdateEntity(RealmDeviceEntity entity) async {
    var result =
        realm.all<RealmDeviceEntity>().query("address == '${entity.address}'");
    await realm.writeAsync(() {
      if (result.isEmpty) {
        realm.add(entity, update: false);
      } else {
        entity.id = result.first.id;
        realm.add(entity, update: true);
      }
    });
    result =
        realm.all<RealmDeviceEntity>().query("address == '${entity.address}'");
    return result.first.id;
  }
}
